#include <all_wlib.h>
#pragma hdrstop
//#pragma package(smart_init)

#include "int.h"

//---------------------------------------------------------------------------
//  UTILS
//---------------------------------------------------------------------------
void Val2DMS( double val, double& d, double& m, double& s )
  {
     d = (int)val;   val = (val-((int)val)) * 100;
     m = val*60/100; val = (m - ((int)m)) * 100;
     s = val*60/100;
}

void Val2DM( double val, double& d, double& m )
  {
     d = (int)val;     val = (val-((int)val)) * 100;
     m = val*60/100;
}

bool DMS2Val( double d, double m, double s, double& v )
  {
     if ( d < -180. || d > 180. ||
          m < 0.0001 || m > 60. ||
          s < 0.0001 || s > 60. )
       return false;

     if ( d < 0 )
       v = d - (m*100/60)/100 - (s*100/60)/10000;
      else
       v = d + (m*100/60)/100 + (s*100/60)/10000;

 return true;
}

bool DM2Val( double d, double m, double& v )
  {
     if ( d < -180. || d > 180. ||
          m < 0.0001 || m > 60. )
       return false;

     if ( d < 0 )
       v = d - (m*100/60)/100;
      else
       v = d + (m*100/60)/100;

 return true;
}

void ozi2UTM( double Lat, double Lon, int& E, int& N )
  {  char   *dat = NULL;
     char   *zone = NULL;
     double  cLon, _n, _e;

     cLon = ((int)Lon) / 3;
     cLon = cLon * 3 + 3;

     oziConvertLL2Grid( OZ_GRID_UTM, Lat, Lon, dat, zone, _e, _n, 0, cLon, 0, 0, 1, 500000, 0 );
     N = _n;
     E = _e;
}

CONSTSTR TimeStr( time_t v )
  {  static char buff[ 50 ];
     struct tm ctm,
               *ttm;
     time_t    t;

     time( &t );
     ctm = *localtime( &t );

     ttm = localtime(&v);

     if ( ctm.tm_mday != ttm->tm_mday ||
          ctm.tm_mon  != ttm->tm_mon  ||
          ctm.tm_year != ttm->tm_year )
       strftime( buff,sizeof(buff),"%d/%m/%Y %H:%M:%S", ttm );
      else
       strftime( buff,sizeof(buff),"%H:%M:%S",ttm );

 return buff;
}

CONSTSTR TimeDiffStr( time_t v )
  {  static char buff[ 50 ];

     if ( v > 3600 )
       SNprintf( buff, sizeof(buff), "%02d:%02d:%02d", v/3600, (v%3600)/60, (v%3600)%60 );
      else
       SNprintf( buff, sizeof(buff), "%02d:%02d", v/60, v%60 );
 return buff;
}

TControl *FindControl( TWinControl *wc, CONSTSTR nm )
  {
     for( int n = 0; n < wc->ControlCount; n++ ) {
       TControl *ctl = wc->Controls[n];
       if ( StrCmp( nm, ctl->Name.c_str(), -1, TRUE ) == 0 )
         return ctl;

       TWinControl *w = dynamic_cast<TWinControl*>( ctl );
       if ( w ) {
         ctl = FindControl( w, nm );
         if ( ctl )
           return ctl;
       }
     }
 return NULL;
}

static const char *fmt_chars  = "mkM";
#define FMT_SIZE 3

CONSTSTR FormatKm( double val )
  {  static char buff[ 40 ];

     int charnum = 0;
     while( val >= 1000. ) {
       charnum++;
       val /= 1000;
     }

     if ( !charnum )           Sprintf( buff,"%d",(int)val ); else
     if ( charnum < FMT_SIZE ) Sprintf( buff,"%.3lf%c",val,fmt_chars[charnum] ); else
       Sprintf( buff,"%.3lf?",val );

 return buff;
}

//---------------------------------------------------------------------------
//  ControlOverride
//---------------------------------------------------------------------------
__fastcall ControlOverride::ControlOverride( void )
  {
     Ctl       = NULL;
     Font0Used  = false;
     Font0      = new TFont;
     Font1Used  = false;
     Font1      = new TFont;
     Color0Used = false;
     Color0     = clNone;
     Color1Used = false;
     Color1     = clNone;
}
__fastcall ControlOverride::~ControlOverride()
  {
    delete Font0;
    delete Font1;
}
//---------------------------------------------------------------------------
//  OverrideArray
//---------------------------------------------------------------------------
__fastcall OverrideArray::OverrideArray( void )
    : MyArray<PControlOverride>( 10,TRUE,10 )
  {
     OnControlChange = NULL;
}

PControlOverride __fastcall OverrideArray::Find( TControl *ctl )
  {
     if ( !ctl )
       return NULL;

     for( int n = 0; n < Count(); n++ ) {
       PControlOverride p = Item(n);
       if ( p->Ctl == ctl )
         return p;
     }
 return NULL;
}

PControlOverride __fastcall OverrideArray::AddFind( TControl *ctl )
  {  PControlOverride p = Find(ctl);
     if ( p )
       return p;
     p = Add( new ControlOverride );
     p->Ctl = ctl;

 return p;
}

void __fastcall OverrideArray::Notify( TControl *ctl )
  {
    if ( OnControlChange ) OnControlChange( ctl );
}

void __fastcall OverrideArray::OverrideFont( TControl *ctl, int num )
  {
     if ( !ctl )
       return;

     HAutoPtr<TFontDialog> d( new TFontDialog(NULL) );

     PHCustomGrid grid = dynamic_cast<PHCustomGrid>(ctl);

     if ( grid )
       d->Font->Assign( num == 0 ? grid->CellFont : grid->HeaderFont );
      else
       d->Font->Assign( ((ControlAccess*)ctl)->Font );

     d->Options = TFontDialogOptions() << fdEffects << fdForceFontExist;
     if ( !d->Execute() ) return;

     PControlOverride p = AddFind( ctl );

     if ( grid ) {
       if ( num == 0 )
         grid->CellFont->Assign( d->Font );
        else
         grid->HeaderFont->Assign( d->Font );
     } else
       ((ControlAccess*)ctl)->Font->Assign( d->Font );

     if ( num == 0 ) {
       p->Font0Used = true;
       p->Font0->Assign( d->Font );
     } else {
       p->Font1Used = true;
       p->Font1->Assign( d->Font );
     }
     Notify( p->Ctl );
}

void __fastcall OverrideArray::OverrideColor( TControl *ctl, int num )
  {
     if ( !ctl )
       return;

     HAutoPtr<TColorDialog> d( new TColorDialog(NULL) );
     PHCustomGrid           grid = dynamic_cast<PHCustomGrid>(ctl);

     if ( grid )
       d->Color = num == 0 ? grid->CellColor : grid->HeaderColor;
      else
       d->Color = ((ControlAccess*)ctl)->Color;

     d->Options = TColorDialogOptions() << cdFullOpen << cdAnyColor;
     if ( !d->Execute() ) return;

     PControlOverride p = AddFind( ctl );

     if ( grid ) {
       if ( num == 0 )
         grid->CellColor = d->Color;
        else
         grid->HeaderColor = d->Color;
     } else
       ((ControlAccess*)ctl)->Color = d->Color;

     if ( num == 0 ) {
       p->Color0Used = true;
       p->Color0     = d->Color;
     } else {
       p->Color1Used = true;
       p->Color1     = d->Color;
     }
     Notify( p->Ctl );
}

void __fastcall OverrideArray::idFont(TObject *Sender)  { OverrideFont( PopupControl, ((PTMenuItem)Sender)->Tag ); }
void __fastcall OverrideArray::idColor(TObject *Sender) { OverrideColor( PopupControl, ((PTMenuItem)Sender)->Tag ); }

void __fastcall OverrideArray::PrepareOverridePopup( TMenuItem *mnu )
  {
     PrepareOverridePopup( mnu, FindDragTarget( Mouse->CursorPos, true ) );
}

void __fastcall OverrideArray::PrepareOverridePopup( TMenuItem *mnu, TControl *ctl )
  {
     mnu->Clear();

     PopupControl = ctl;
     if ( !PopupControl )
       return;

     TMenuItem *mi;

     mnu->Add( mi = new TMenuItem(mnu) );
       mi->Caption = PopupControl->Name;
       mi->Enabled = false;
     mnu->Add( mi = new TMenuItem(mnu) );
       mi->Caption = "-";
       mi->Enabled = false;
     mnu->Add( mi = new TMenuItem(mnu) );
       mi->Caption = LNG("Set font...");
       mi->OnClick = idFont;
       mi->Tag     = 0;
     mnu->Add( mi = new TMenuItem(mnu) );
       mi->Caption = LNG("Set color...");
       mi->OnClick = idColor;
       mi->Tag     = 0;
     if ( dynamic_cast<PHCustomGrid>(ctl) ) {
       mnu->Add( mi = new TMenuItem(mnu) );
         mi->Caption = LNG("Set hader font...");
         mi->OnClick = idFont;
         mi->Tag     = 1;
       mnu->Add( mi = new TMenuItem(mnu) );
         mi->Caption = LNG("Set hader color...");
         mi->OnClick = idColor;
         mi->Tag     = 1;
     }
}

void __fastcall OverrideArray::Save( PHConfigItem cfg )
  {  PControlOverride p;
     PHConfigItem     pc;
     int              n, cn;

     cfg->Clear();
     for( cn = 0, n = 0; n < Count(); n++ ) {
       p = Item(n);
       if ( !p->Color0Used && !p->Font0Used &&
            !p->Color1Used && !p->Font1Used )
         continue;

       pc = cfg->ConfigGetCreate( Message("Item%d",n) );

       //Name
       pc->Write( "Name", p->Ctl->Name.c_str() );

       //Font
       pc->Write( "FontUsed", p->Font0Used );
       if ( p->Font0Used )
         HSaveFont( p->Font0, pc->ConfigGetCreate( "Font" ) );

       pc->Write( "Font1Used", p->Font1Used );
       if ( p->Font1Used )
         HSaveFont( p->Font1, pc->ConfigGetCreate( "Font1" ) );

       //Color
       pc->Write( "ColorUsed", p->Color0Used );
       if ( p->Color0Used )
         pc->Write( "Color", p->Color0 );

       pc->Write( "Color1Used", p->Color1Used );
       if ( p->Color1Used )
         pc->Write( "Color1", p->Color1 );

       cn++;
     }

     //Write real overrides count
     cfg->Write( "Count", cn );
}

void __fastcall OverrideArray::Load( TWinControl *Base, PHConfigItem cfg )
  {  int cn = cfg->Read( "Count", 0 ),
         n;
     TFont *Font;

     if ( cn )
       __try{
         Font = new TFont;

         for( n = 0; n < cn; n++ ) {
           PHConfigItem pc = cfg->ConfigGetCreate( Message("Item%d",n) );
           CONSTSTR     nm = pc->Read( "Name", "" );
           if ( !nm || !nm[0] ) continue;

           TControl *ctl = FindControl( Base, nm );
           if ( !ctl ) continue;

           //New override
           PControlOverride p = AddFind( ctl );
           if ( !p ) continue;

           //Font
           p->Font0Used = pc->Read( "FontUsed", false );
           if ( p->Font0Used )
             HLoadFont( p->Font0, pc->ConfigGetCreate( "Font" ) );

           p->Font1Used = pc->Read( "Font1Used", false );
           if ( p->Font1Used )
             HLoadFont( p->Font1, pc->ConfigGetCreate( "Font1" ) );

           //Color
           p->Color0Used = pc->Read( "ColorUsed", false );
           if ( p->Color0Used )
             p->Color0 = (TColor)pc->Read( "Color", clNone );

           p->Color1Used = pc->Read( "Color1Used", false );
           if ( p->Color1Used )
             p->Color1 = (TColor)pc->Read( "Color1", clNone );

           //Assign loaded values
           if ( p->Font0Used || p->Font1Used ) {
             PHCustomGrid grid = dynamic_cast<PHCustomGrid>( p->Ctl );
             if ( grid ) {
               if ( p->Font0Used ) grid->CellFont   = p->Font0;
               if ( p->Font1Used ) grid->HeaderFont = p->Font1;
             } else
               ((ControlAccess*)p->Ctl)->Font = p->Font0;
           }

           if ( p->Color0Used || p->Color1Used ) {
             PHCustomGrid grid = dynamic_cast<PHCustomGrid>( p->Ctl );
             if ( grid ) {
               if ( p->Color0Used ) grid->CellColor   = p->Color0;
               if ( p->Color1Used ) grid->HeaderColor = p->Color1;
             } else
               ((ControlAccess*)p->Ctl)->Color = p->Color0;
           }

           //Notify controls changes
           Notify( p->Ctl );
         }
       }__finally{
         delete Font;
       }
}


//---------------------------------------------------------------------------
//  HCoord
//---------------------------------------------------------------------------
int HCoord::Size( const HCoord& p )
  {
    if ( p.x == x && p.y == y )
      return 0;

    int vX = p.x-x;
    if ( vX > 20000 || vX < -20000 )
      return 0;

    int vY = p.y-y;
    if ( vY > 20000 || vY < -20000 )
      return 0;

    int v = vX*vX + vY*vY;
    if ( v <= 0 )
      return 0;

 return sqrt( v );
}

int HCoord::QSize( const HCoord& p )
  {
    if ( p.x == x && p.y == y )
      return 0;

    int vX = p.x-x;
    if ( vX > 20000 || vX < -20000 )
      return 0;

    int vY = p.y-y;
    if ( vY > 20000 || vY < -20000 )
      return 0;

    int v = vX*vX + vY*vY;
    if ( v <= 0 )
      return 0;

 return v;
}
//---------------------------------------------------------------------------
//  HCoordLine
//---------------------------------------------------------------------------
HCoordLine::HCoordLine( void )
   : MyRefArray<HCoord>( 10,100 )
  {
}

void HCoordLine::AddPoint( double lat, double lon, int x, int y, int avg )
  {  PHCoord p = Count() ? LastObject() : (&Start);

     if ( !p->Diff( x,y,avg ) )
       return;

     p = Add( HCoord( lat,lon,x,y ) );
     p->Measure = time(NULL);
}

int HCoordLine::DirectSize( void )
  {
 return Count() ? Start.Size( *LastObject() ) : 0;
}

PHCoord HCoordLine::LastPoint( void )
  {
  return Count() ? Item( Count()-1 ) : (&Start);
}

int HCoordLine::Size( void )
  {  PHCoord p = &Start,
             p1;
     int     sz = 0;

     for( int n = 0; n < Count(); n++, p = p1 ) {
       p1 = Item(n);
       sz += p->Size( *p1 );
     }
 return sz;
}

bool HCoordLine::Save( HOStream& s )
  {  DWORD id;

     id = Count();
     if ( !s.Write( &id,sizeof(id) ) ||
          !s.Write( &Start,sizeof(Start) ) )
       return false;

     for( int n = 0; n < Count(); n++ ) {
       PHCoord p = Item(n);
       if ( !s.Write( p, sizeof(*p) ) )
         return false;
     }

 return true;
}

bool HCoordLine::Load( HIStream& s )
  {  DWORD id;

     DeleteAll();
     if ( !s.Read( &id,sizeof(id) ) ||
          !s.Read( &Start,sizeof(Start) ) )
       return false;

     for( int n = 0; n < (int)id; n++ ) {
       PHCoord p = Add( HCoord() );
       if ( !s.Read( p, sizeof(*p) ) )
         return false;
     }

 return true;
}

//---------------------------------------------------------------------------
//  HCoordPath
//---------------------------------------------------------------------------
HCoordPath::HCoordPath( void )
   : MyArray<PHCoordLine>( 10,TRUE,10 )
  {
}

bool HCoordPath::Save( HOStream& s )
  {  DWORD id = COORDPATH_ID;

   //ID
     if ( !s.Write( &id,sizeof(id) ) )
       return false;

   //Lines
     id = Count();
     if ( !s.Write( &id,sizeof(id) ) )
       return false;

     id = COORDLINE_ID;
     for( int n = 0; n < Count(); n++ )
       if ( !s.Write( &id,sizeof(id) ) ||
            !Item(n)->Save(s) )
         return false;

   //Places
     id = COORPLACE_ID;
     if ( !s.Write( &id,sizeof(id) ) ||
          !Places.Save(s) )
       return false;


 return true;
}

bool HCoordPath::Load( HIStream& s )
  {  DWORD id;

     DeleteAll();

   //path ID
     if ( !s.Read( &id,sizeof(id) ) )
       return false;
     if ( id != COORDPATH_ID ) {
       FIO_SETERRORN( ERROR_HEADER );
       return false;
     }

   //path lines
     DWORD cn;
     if ( !s.Read( &cn,sizeof(cn) ) )
       return false;

     for( int n = 0; n < (int)cn; n++ ) {
       if ( !s.Read( &id,sizeof(id) ) )
         return false;
       if ( id != COORDLINE_ID ) {
         FIO_SETERRORN( ERROR_HEADER );
         return false;
       }

       PHCoordLine l = Add( new HCoordLine );
       if ( !l->Load(s) )
         return false;
     }

   //Places
     if ( s.Read( &id,sizeof(id) ) && id == COORPLACE_ID )
       if ( !Places.Load(s) )
         return false;

 return true;
}

void ForceHint( TObject *Sender, int x, int y )
  {  TControl *ctl = dynamic_cast<TControl*>(Sender);

     if ( !ctl ) return;

     TPoint p;

     if ( x == -1 ) p.x = 1; else p.x = x;
     if ( y == -1 ) p.y = 1; else p.y = y;

     p = ctl->ClientToScreen( p );
     Application->ActivateHint( p );
}